

#ifndef __MISC_UTIL_H__
#define __MISC_UTIL_H__

#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
#define EXTERNC	extern "C"
#else
#define EXTERNC
#endif


#define ARRAYOF(a) (sizeof(a)/sizeof(a[0]))
#define ENDIAN_DWORD_SWITCH(e) ( (((e)&0xff)<<24)| (((e)&0xff00)<<8) | (((e)&0xff0000)>>8) | (((e)&0xff000000)>>24) )

#define INVALID_DWORD ((DWORD)(-1))

#ifndef ASSERT
#define ASSERT _ASSERTE
#endif
#ifndef VERIFY
#ifdef _DEBUG
#define VERIFY _ASSERTE
#else
#define VERIFY(f)          ((void)(f))
#endif
#endif
//#include <crtdbg.h>


//
// TCHAR* __FILE__
#ifdef UNICODE
#define __TFILE__ _TFILE1_(__FILE__)
#else
#define __TFILE__ __FILE__
#endif
#define _TFILE2_(file) L##file
#define _TFILE1_(file) _TFILE2_(file)


#ifdef UNICODE
#define __TFUNCDNAME__ _TFUNCDNAME1_(__FUNCDNAME__)
#else
#define __TFUNCDNAME__ __FUNCDNAME__
#endif
#define _TFUNCDNAME2_(fun) L##fun
#define _TFUNCDNAME1_(fun) _TFILE2_(fun)
	

//
// TCHAR* __LINE__
#define __TCLINE__ _TCLINE1_(__LINE__)
#ifdef UNICODE
#define _TCLINE2_(line) L###line
#else
#define _TCLINE2_(line) #line
#endif
#define _TCLINE1_(line) _TCLINE2_(line)



DWORD EatWhite(const TCHAR* pstr);
DWORD FindWhite(const TCHAR* pstr, DWORD idEnd);
DWORD FindCharS(const TCHAR* pstr, const TCHAR* pchS, DWORD dwCharNumb, DWORD idEnd);

//
// convert variable para "format ..." to a single buffer
int _cdecl ExpToBuf(TCHAR* pbuf, DWORD dwSize, const TCHAR* format, ...);
//
// convert variable para "format ..." to a single buffer
// !note to "free" the returned "malloc" buffer !
TCHAR* ExpToMallocBuf(const TCHAR* format, ...);

DWORD _cdecl CallFunV(DWORD dwFnAddr, DWORD dwParaDwNumb, ...);
DWORD _cdecl CallFun(DWORD dwFnAddr, DWORD dwParaDwNumb, DWORD* pdwParaS);

// asm utility functions
DWORD Swap(DWORD* pdwAddr, DWORD dwNewVal);


#define BUF_FUN_CALL_TAG 0x436e7546	//"FunC"
#define FUN_CALL_PARA_TYPE_VAL	0
#define FUN_CALL_PARA_TYPE_PTR	1
int _cdecl BufFunCallInfo(DWORD* pbuf, DWORD dwBufSize, DWORD* pdwSizeNeed, void* pFn, DWORD dwParaCnt, ...);
int CallFunInfoBuf(DWORD* pbuf, DWORD dwBufDim, DWORD* pRet);

VOID PerfermCntToSMN(LARGE_INTEGER* pliCnt, LARGE_INTEGER* pliFrq, DWORD* pdwS, DWORD* pdwMS, DWORD* pdwNS);

#ifdef KERNEL_LIB
#ifdef _vsntprintf
#undef _vsntprintf
#endif	//#ifdef _vsntprintf
#define _vsntprintf NK_sntprintf
#ifdef _sntprintf
#undef _sntprintf
#endif	//#ifdef _sntprintf
#define _sntprintf NK_sntprintf

#define QueryPerformanceFrequency SC_QueryPerformanceFrequency
extern BOOL SC_QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
#define QueryPerformanceCounter SC_QueryPerformanceCounter
extern BOOL QueryPerformanceCounter(LARGE_INTEGER *lpFrequency);
// used for kernel
int NK_sntprintf(LPWSTR buffer, DWORD maxChars, LPCWSTR format, ...);
#endif #ifdef KERNEL_LIB

#ifdef __cplusplus
}
#endif


#ifdef __cplusplus
/*
#ifdef UNICODE
#define _tstring std::wstring
#else
#define _tstring std::string
#endif
*/
#include <string>
typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> > _tstring;

#ifdef MS_VC_CMPILE
#include <sstream>
typedef std::basic_stringstream<TCHAR> _tstringstream;
typedef std::basic_istringstream<TCHAR> _tistringstream;


template <class T>
VOID String2Var(_tstring* pstr, T* pt)
{
	if(pstr->empty())
	{
		*pt=(T)(0);
		return;
	}

	_tstringstream tss(*pstr);

	if(pstr->size()>2)
	{
		if( ('0'==(*pstr)[0])
			 && ( ('x'==(*pstr)[1]) || ('X'==(*pstr)[1]) ) )
		{
			tss>>hex>>*pt;
		}
	}

	tss>>*pt;
}

template <>
VOID String2Var<_tstring>(_tstring* pstr, _tstring* pt);

template <class T>
VOID Var2String(T* pt, _tstring* pstr)
{
	_tstringstream _tss;
	_tss<<*pt;
	*pstr=_tss.str();	
}

template <>
VOID Var2String<_tstring>(_tstring* pt, _tstring* pstr);

#else	//#ifdef MS_VC_CMPILE

template <class T>
VOID String2Var(_tstring* pstr, T* pt);

template <class T>
VOID Var2String(T* pt, _tstring* pstr);

#endif	//#ifdef MS_VC_CMPILE

//
//  function object used to find pair
template<class T>
class FnObFindPairEnd
{
public:
	FnObFindPairEnd(T tPairBgn, T tPairEnd)
	: m_tPairBgn(tPairBgn), m_tPairEnd(tPairEnd)
	, m_iPairRcs(0)
	{};

public:
	bool operator()(T t)
	{
		if(t==m_tPairBgn)
		{
			m_iPairRcs++;
			return false;
		}
		if(t==m_tPairEnd)
		{
			if(m_iPairRcs==0)
			{
				return true;
			}
			else
			{
				m_iPairRcs--;
				return false;
			}
		}
		return false;
	};

private:
	T m_tPairBgn;
	T m_tPairEnd;

	int m_iPairRcs;
};



//
// method function object, used to call method function on stl algorithm
//
template<class _Cls		// class type
		,class _Result	// function return type
		,class _Arg>	// function parameter type
class met_fun_p1r_t
{
public:
	explicit met_fun_p1r_t(_Cls* _Pci, _Result (_Cls::*_Pm)(_Arg))
						:_Pmetfun(_Pm)
						,_Pclsins(_Pci)
	{};

	_Result operator()(_Arg& _Pa) const
	{	// call function
		return ((_Pclsins->*_Pmetfun)(_Pa));
	}
private:
	_Result (_Cls::*_Pmetfun)(_Arg);	// the member function pointer
	_Cls* _Pclsins;
};

template<class _Cls		// class type
		,class _Result	// function return type
		,class _Arg>	// function parameter type
inline met_fun_p1r_t<_Cls, _Result, _Arg> met_fun_p1r(_Cls* _Pci, _Result (_Cls::*_Pm)(_Arg))
{	// return a mem_fun1_t functor adapter
	return (met_fun_p1r_t<_Cls, _Result, _Arg>(_Pci, _Pm));
}


template<class _Result	// function return type
//		, class _Ty		// function parameter type
		, class _Arg1	// the first parameter type, set by stl algorithm
		, class _Arg2	// the second parameter, set by user
		, class _Cls>	// class type
class met_fun_p2r_t
	//	: public unary_function<_Ty *, _Result>
{
public:
	explicit met_fun_p2r_t(_Cls* _Pci, _Result (_Cls::*_Pm)(_Arg1, _Arg2))
		:_Pmetfun(_Pm)
		,_Pclsins(_Pci)
	{};

	_Result operator()(_Arg1& _Pa1, _Arg2& _Pa2) const
	{	// call function
		return ((_Pclsins->*_Pmetfun)(_Pa1, _Pa2));
	}
private:
	_Result (_Cls::*_Pmetfun)(_Arg1, _Arg2);	// the member function pointer
	_Cls* _Pclsins;
};
template<class _Result	// function return type
		, class _Arg1	// the first parameter type, set by stl algorithm
		, class _Arg2	// the second parameter, set by user
		, class _Cls>	// class type
inline met_fun_p2r_t<_Cls, _Result, _Arg1, _Arg2> met_fun_p2r(_Cls* _Pci, _Result (_Cls::*_Pm)(_Arg1, _Arg2))
{	// return a mem_fun1_t functor adapter
	return (met_fun_p2r_t<_Cls, _Result, _Arg1, _Arg2>(_Pci, _Pm));
}

//
// utils for facility find element in segment specialfied by "__declspec allocate"
//
template<class T, class _Pr>
bool FindEleInSeg(int* pSegStar, int* pSegEnd, _Pr _Pred, T** ppBng, T** ppEnd)
{
	int *piFind;
	T* pt;

	// find the a valid element
	for(piFind=pSegStar; piFind<pSegEnd; piFind++)
	{
		pt=(T*)piFind;
		if(_Pred(pt))
		{
			*ppBng=pt;
			break;
		}
	}

	// not find any element
	if(piFind>=pSegEnd)
	{
		return false;
	}

	for(; (int*)pt<pSegEnd; pt++)
	{
		// the first invalid element, should be the end of segment;
		if(!_Pred(pt))
		{
			break;
		}
	}
	
	*ppEnd=pt;
	return true;
}

#endif  //#ifdef __cplusplus

//
//==== implements ====
//
#if (defined(MISCUTIL_IMP)|defined(KEN_LIB_IMP))

#ifdef __cplusplus

template <>
VOID String2Var<_tstring>(_tstring* pstr, _tstring* pt)
{
	*pt=*pstr;
}

template <>
VOID Var2String<_tstring>(_tstring* pt, _tstring* pstr)
{
	*pstr=*pt;
}

#endif  //#ifdef __cplusplus

DWORD EatWhite(const TCHAR* pstr)
{
	DWORD dwEatNumb=0;
	for( ;
		( (0!=pstr[dwEatNumb])
		&& ((' '==pstr[dwEatNumb]) || ('\t'==pstr[dwEatNumb])) );
		dwEatNumb++)
	{
	}
	
	return dwEatNumb;
}

DWORD FindWhite(const TCHAR* pstr, DWORD idEnd)
{
	static TCHAR chWhiteS[]={_T(' '), _T('\t')};
	return FindCharS(pstr, chWhiteS, ARRAYOF(chWhiteS), idEnd);
}

DWORD FindCharS(const TCHAR* pstr, const TCHAR* pchS, DWORD dwCharNumb, DWORD idEnd)
{
	DWORD i, j;
	for(i=0; 0!=pstr[i]; i++)
	{
		if( (0!=idEnd) && (i>=idEnd) )
		{
			break;
		}

		for( j=0; j<dwCharNumb; j++)
		{
			if(pstr[i]==pchS[j])
			return i;
		}
	}
	
	return INVALID_DWORD;
}

//
// convert variable para "format ..." to a single buffer
int _cdecl ExpToBuf(TCHAR* pbuf, DWORD dwSize, const TCHAR* format, ...)
{
	int ret;
	va_list arglist;
	va_start(arglist, format);
	ret=_vsntprintf(pbuf, dwSize, format, arglist);
    va_end(arglist);

	return ret;
}

#ifndef KERNEL_LIB
//
// convert variable para "format ..." to a single buffer
// !note to "free" the returned "malloc" buffer !
TCHAR* ExpToMallocBuf(const TCHAR* format, ...)
{
	TCHAR buf[4096];
	int iSize;
	TCHAR* ret;

	va_list arglist;
	va_start(arglist, format);
	iSize=_vsntprintf(buf, ARRAYOF(buf), format, arglist);
    va_end(arglist);

	if(-1==iSize)
	{
		iSize=sizeof(buf);	// too large
	}
	iSize++;
	iSize*=sizeof(TCHAR);

	ret=(TCHAR*)malloc(iSize);
	_tcsncpy(ret, buf, iSize);
	return ret;
}
#endif	//#ifndef KERNEL_LIB

int _cdecl BufFunCallInfo(DWORD* pbuf, DWORD dwBufSize, DWORD* pdwSizeNeed, void* pFn, DWORD dwParaCnt, ...)
{
	DWORD i;
	va_list arglist;

	if(pdwSizeNeed)
	{
		*pdwSizeNeed=(1+1+1+dwParaCnt*2);
	}

	if(dwBufSize<(1+1+1+dwParaCnt*2) )
	{
		return -1;
	}
	
	pbuf[0]=BUF_FUN_CALL_TAG;	// the return value when return
	pbuf[1]=(DWORD)pFn;
	pbuf[2]=dwParaCnt;
	pbuf+=3;

	va_start(arglist, dwParaCnt);
	for(i=0; i<dwParaCnt; i++)
	{
		pbuf[i]=va_arg(arglist, DWORD);	// para
		pbuf[dwParaCnt+i]=va_arg(arglist, DWORD);	// para type
	}
    va_end(arglist);
    
    return 0;
}

//this function ignore pata type
int CallFunInfoBuf(DWORD* pbuf, DWORD dwBufDim, DWORD* pRet)
{
	if( (NULL==pbuf)
		|| (BUF_FUN_CALL_TAG!=pbuf[0])
		|| (dwBufDim<3)
		|| (dwBufDim<(3+pbuf[2])) )
	{
		return -1;
	}
	
	
	pbuf[0]=CallFun(pbuf[1], pbuf[2], pbuf+3);
	if(pRet)
	{
		*pRet=pbuf[0];
	}

	return 0;
}

#pragma warning( push )
#pragma warning(disable : 4312)
DWORD _cdecl CallFunV(DWORD dwFnAddr, DWORD dwParaDwNumb, ...)
{
	DWORD dwParaS[9];
	DWORD i;
	va_list arglist;

	
	va_start(arglist, dwParaDwNumb);
	for(i=0; i<dwParaDwNumb; i++)
	{
		dwParaS[i]=va_arg(arglist, DWORD);	// para
	}
    va_end(arglist);

	switch (dwParaDwNumb)
	{
	case 0:
		return (*((DWORD (*)())(dwFnAddr)))();

	case 1:
		return (*((DWORD (*)(DWORD))(dwFnAddr)))(dwParaS[0]);

	case 2:
		return (*((DWORD (*)(DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1]);

	case 3:
		return (*((DWORD (*)(DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2]);

	case 4:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3]);

	case 5:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3], dwParaS[4]);

	case 6:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3], dwParaS[4], dwParaS[5]);

	case 7:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3], dwParaS[4], dwParaS[5], dwParaS[6]);

	case 8:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3], dwParaS[4], dwParaS[5], dwParaS[6], dwParaS[7]);

	case 9:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(dwParaS[0], dwParaS[1], dwParaS[2], dwParaS[3], dwParaS[4], dwParaS[5], dwParaS[6], dwParaS[7], dwParaS[8]);

	// not implement, raise a exception
	default:
		return (*((DWORD (*)())(0)))();
	}
	
}

DWORD _cdecl CallFun(DWORD dwFnAddr, DWORD dwParaDwNumb, DWORD* pdwParaS)
{
	switch (dwParaDwNumb)
	{
	case 0:
		return (*((DWORD (*)())(dwFnAddr)))();

	case 1:
		return (*((DWORD (*)(DWORD))(dwFnAddr)))(pdwParaS[0]);

	case 2:
		return (*((DWORD (*)(DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1]);

	case 3:
		return (*((DWORD (*)(DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2]);

	case 4:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3]);

	case 5:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4]);

	case 6:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5]);

	case 7:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6]);

	case 8:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6], pdwParaS[7]);

	case 9:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6], pdwParaS[7], pdwParaS[8]);

	// not implement, raise a exception
	default:
		return (*((DWORD (*)())(0)))();
	}
}
#pragma warning( pop ) //#pragma warning(disable : 4312)


VOID PerfermCntToSMN(LARGE_INTEGER* pliCnt, LARGE_INTEGER* pliFrq, DWORD* pdwS, DWORD* pdwMS, DWORD* pdwNS)
{
    *pdwS=(DWORD)(pliCnt->QuadPart/(pliFrq->QuadPart));
    pliCnt->QuadPart-=(*pdwS*pliFrq->QuadPart);
    *pdwMS=(DWORD)((pliCnt->QuadPart*1000)/pliFrq->QuadPart);
    pliCnt->QuadPart-=(*pdwMS*(pliFrq->QuadPart/1000));
    *pdwNS=(DWORD)((pliCnt->QuadPart*1000*1000)/pliFrq->QuadPart);
}


#ifdef KERNEL_LIB
int NK_sntprintf(LPWSTR buffer, DWORD maxChars, LPCWSTR format, ...)
{
	int ret;
    va_list pArgList;
    
    va_start(pArgList, format);
    ret=NKwvsprintfW(buffer, format, pArgList, maxChars);
	va_end(pArgList);

	return ret;
}

wchar_t *wcsrchr( const wchar_t *string, wchar_t c )
{
	DWORD i, dwId=0xffffffff;
	for(i=0; 0!=string[i]; i++)
	{
		if(c==string[i])
		{
			dwId=i;
		}
	}

	if(0xffffffff!=dwId)
	{
		return (wchar_t *)(string+dwId);
	}
	else
	{
		return NULL;
	}
}

#endif	//#ifdef KERNEL_LIB


#endif  //#if (defined(MISCUTIL_IMP)|defined(KEN_LIB_IMP))



#endif	//#ifndef __MISC_UTIL_H__

